/*
 * weight_sensor_amp.c
 *
 * Created: 28/02/2012 10:52:13
 *  Author: Dani
 */ 

#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>
#include <avr/interrupt.h>
#include "weight_sensor_sampling.h"

#define SIMULATE_PARAMETER_VALUE 0b00000001
#define SECOND_STAGE_GAIN_CODE   0b00000000
#define FIRST_STAGE_GAIN_CODE    0b00000001
#define OUTPUT_OFFSET_CODE       0b00000010

#define VOUT 0
#define FILT 1
#define DIGI_IN 2

uint8_t i = 0;
uint16_t tara = 0;
uint32_t measure = 0;
int16_t weight[NUM_SAMPLES2]; // Can be negative
int32_t weight_mean = 0;

/*
void WeightFiltering()
{
	// Noise filtering: 200 samples.
	// Tested at 2, 10, 64, 100, 200, 255 and 500 samples.
	// Process time: 8 us * NUM_SAMPLES. 200 samples -> 1,6 ms.
	// 32 bits variable because of the number of samples used
	// 1024 * 200 = 204800 < 2^32	
	
	measure += ADCW;
	i++;
	if (i == NUM_SAMPLES1)
	{
		// Second filtering
		// If there are two different values, the result will be the lower one.
		for (uint8_t j = (NUM_SAMPLES2 - 1); j > 0; j--)
		{
				weight_mean += weight[j];
				weight[j] = weight [j - 1];
		}
		weight[0] = (measure/NUM_SAMPLES1);
		weight_mean = (weight_mean + weight[0])/NUM_SAMPLES2;	
		
		i = 0;
		measure = 0;		
	}				
}

uint16_t WeightRead()
{			
	return (weight_mean - tara);	
}
*/

void ADCInit()
{
	// External AREF reference, ADLAR = 0, Input = ADC0 single ended
	//ADMUX = 0b00000000;
	ADMUX = 0b10000000;
	// ADC enable
	// Start conversion
	// ADC interrupt disaabled
	// ADC prescaler = 64 (=> ADC clock = 8 MHz / 64 = 125 kHZ)
	// OBS : Bit ADATE = 0.
	 ADCSRA = 0b10000110;
}

void WeightSensorInit()
{
	// Prepare pin DIGIN (output from Mega16, starting low) 
	AMP_PORT &= ~(1<<DIGI_IN);  // ---------- simplify?
	AMP_DDR |= (1<<DIGI_IN);
	// Sensor amplifier : First stage gain ~ 5 (60)
	setFirstStageGain(127);
	// Sensor amplifier : Second stage gain = 200
	setSecondStageGain(7);
	// Sensor amplifier : Offset = 0 volt
	setOutputOffset(0);
	
	ADCInit();	
	// Wait for the weight sensor to have the first measure.
	// Sei must set before driver's initialization.
	//_delay_ms(1000);
	//tara = WeightRead();
}


/*-----------------------------------------------------------------------
Signal Amplifier AD8555
----------------------------------------------------------------------*/

void sendData(uint8_t data)
{
	// Disable interrupts
	cli();
	// Set pin DIGIN high
	AMP_PORT |= 1<<DIGI_IN; 
	if (data != 0)
	{
		// If data = 1: Minimum 50uS delay
		_delay_us(51);
	}else
	{
		// If data = 0: Pulse width must be between 50 ns and 10 us
		_delay_us(10);
	}		
	// Set pin DIGIN low
	AMP_PORT &= ~(1<<DIGI_IN);
	sei();
	// Minimum 10uS delay between pulses 
	_delay_us(11);
}

void startOfPacket()
{
	// Send Field 1 (12-Bit Start of Packet 1000 0000 0001)
	sendData(1);
	for (uint8_t i = 0; i < 10; i++)
		sendData(0);
	sendData(1);
}

void endOfPacket()
{
	// Send Field 5 (12-Bit End of Packet 0111 1111 1110)
	sendData(0);
	for (uint8_t i = 0; i < 10; i++)
		sendData(1);
	sendData(0);
}

void sendSensorCommand(uint8_t field_1, uint8_t field_2, uint8_t field_4)
{
	uint8_t i;
	uint8_t mask;
	uint8_t tmp;

  // Send Field 0 (Start of Packet)
  startOfPacket();
  
  // Send Field 1 (2 bit command)
  sendData(field_1 & 0b00000010); 
  sendData(field_1 & 0b00000001);
  
  // Send Field 2 (2 bit command)
  sendData(field_2 & 0b00000010); 
  sendData(field_2 & 0b00000001);
  
  // Send Field 3 (2-Bit Dummy 10)
  sendData(1);
  sendData(0);
  
  // Send Field 4 (8-Bit Value)
  mask = 0b10000000;
  tmp = field_4;
  for (i=0; i<8; i++)
  {
    sendData(tmp & mask);
    mask>>=1;
  }
  // simplify temp?

  // Send Field 5 (End of Packet)
  endOfPacket();
}

void setFirstStageGain(uint8_t gain)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, FIRST_STAGE_GAIN_CODE, (gain & 0x7F));
}

// 0 => 17,5; 7 => 200;
void setSecondStageGain(uint8_t gain)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, SECOND_STAGE_GAIN_CODE, (gain & 0x07));
}
 
// 0 => 0 volt; 255 => 5 volt;
void setOutputOffset(uint8_t offset)
{
  sendSensorCommand(SIMULATE_PARAMETER_VALUE, OUTPUT_OFFSET_CODE, offset);
}
